//---------------------------------------------------------------------
//  This file is part of the Background Motion solution.
// 
//  Copyright (C) Mindscape (TM).  All rights reserved.
//  http://www.mindscape.co.nz
// 
//  THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Data.DLinq;
using System.Expressions;
using System.Query;

using Mindscape.BackgroundMotion.Core.Properties;

namespace Mindscape.BackgroundMotion.Core.Model
{
  /// <summary>
  /// An implementation of the Repository which uses LINQ to SQL Server to persist its data
  /// </summary>
  /// <typeparam name="T">The generic type representing the entity we are dealing with</typeparam>
  /// <remarks>We use a 1 to 1 mapping of entity -> SQL table</remarks>
  public sealed class DLinqRepository<T> : RepositoryBase<T>
    where T : IIdentifiable
  {
    /// <summary>
    /// Returns a count of the items in the repository
    /// </summary>
    /// <returns></returns>
    public override int Count()
    {
      return DataContext.GetTable<T>().Count();
    }

    /// <summary>
    /// Returns a count of the items in the repository which match the supplied lambda
    /// </summary>
    /// <param name="expression">A lambda expression which will be evaluated against the repository</param>
    /// <returns></returns>
    public override int Count(Expression<Func<T, bool>> expression)
    {
      return DataContext.GetTable<T>().Count(expression);
    }

    /// <summary>
    /// Finds a single instance of an entity matching a unique identifier.
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public override T FindOne(int id)
    {
      return FindOne(t => t.Id == id);
    }

    /// <summary>
    /// Finds a single instance of an entity matching a lambda expression
    /// </summary>
    /// <param name="expression"></param>
    /// <returns>
    /// The first entity which matches the expession
    /// </returns>
    public override T FindOne(Expression<Func<T, bool>> expression)
    {
      return DataContext.GetTable<T>().Where(expression).SingleOrDefault();
    }

    /// <summary>
    /// Finds all entities in the repository
    /// </summary>
    /// <returns></returns>
    public override IList<T> FindAll()
    {
      return DataContext.GetTable<T>().ToList();
    }

    /// <summary>
    /// Finds all entities matching a lambda expression
    /// </summary>
    /// <param name="expression">The expression.</param>
    /// <returns></returns>
    public override IList<T> FindAll(Expression<Func<T, bool>> expression)
    {
      return DataContext.GetTable<T>().Where(expression).ToList();
    }

    /// <summary>
    /// Adds a new entity in to the repository
    /// </summary>
    /// <param name="entity"></param>
    public override void Add(T entity)
    {
      DataContext.GetTable<T>().Add(entity);
    }

    /// <summary>
    /// Removes the specified entity from the repository
    /// </summary>
    /// <param name="entity"></param>
    public override void Remove(T entity)
    {
      DataContext.GetTable<T>().Remove(entity);
    }

    /// <summary>
    /// Saves the specified entity back to the repository
    /// </summary>
    /// <param name="entity"></param>
    public override void Save(T entity)
    {
    }

    /// <summary>
    /// Returns a requeryable set of all entities in the repository matching a unique identifier
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public override IQueryable<T> Find(int id)
    {
      return DataContext.GetTable<T>().Where(t => t.Id == id);
    }

    /// <summary>
    /// Returns a requeryable set of all entities in the repository matching a lambda expression
    /// </summary>
    /// <param name="expression"></param>
    /// <returns></returns>
    public override IQueryable<T> Find(Expression<Func<T, bool>> expression)
    {
      return DataContext.GetTable<T>().Where(expression);
    }

    /// <summary>
    /// Returns a requeryable set of all entities in the repository
    /// </summary>
    /// <returns></returns>
    public override IQueryable<T> Find()
    {
     return DataContext.GetTable<T>();
    }

    /// <summary>
    /// Gets the active LINQ DataContext which manages access to the persistance store
    /// </summary>
    private static DataContext DataContext
    {
      get
      {
        DLinqUnitOfWork unitOfWork = UnitOfWork.GetCurrent<DLinqUnitOfWork>();

        if (unitOfWork == null)
        {
          throw new ApplicationException(Resources.NoUnitOfWork);
        }

        return unitOfWork.DataContext;
      }
    }
  }
}